ConcurrentHashMap 详解
在 Java 中经常使用 HashMap,但是它不是线程安全的。在多线程的情况下,会出现数据丢失的问题,如果 JDK 版本小于 1.8,还会出现死循环的问题(死循环的原因可参考 链接)。多线程的场景下建议使用 ConcurrentHashMap。
ConcurrentHashMap 结构图如下:
(图片来自网络,侵删)
ConcurrentHashMap 在 JDK 1.8 前采用分段锁的设计思想,相比 HashTable 直接对读写方法加锁,ConcurrentHashMap 有多把锁,每把锁用于锁住容器中一段数据,当一段数据被一个线程锁住时,其他线程可以访问容器中其他段的数据,有效地提升了并发访问的效率。从 1.8 版本开始,ConcurrentHashMap 放弃了分段锁的设计,底层数据结构为数组+链表+红黑树,通过 volatile、CAS、synchronized控制并发。
下面分析一下 JDK 1.8 版本的 ConcurrentHashMap 的源码。
|
|
通过 put 方法往容器中插入数据:
|
|
initTable 方法对 table 初始化,它借助了 CAS 来保证多线程情况下不重复初始化:
|
|
重点看一下 addCount 方法:
|
|
更新节点总数和扩容的思路有点类似,都允许多个线程分段操作,而不是对整个容器加锁导致只有一个线程操作、其他线程阻塞等待。这种分段的设计思想提高了并发效率。
get 方法比较简单:
|
|
参考链接: